#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int Create_socket(int port)
{
    int ret = 0;
    int sock_fd = -1;
    /*创建套接字*/
    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == sock_fd)
    {
        printf("socket faild,err:%s\n", strerror(errno));
        return -1;
    }
    //设置端口复用
    int opt = 1;
    //setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR,(const void *) &opt,sizeof(opt));
    /*绑定地址*/
    struct sockaddr_in sock_addr;
    sock_addr.sin_family = AF_INET;
    sock_addr.sin_port = htons(port);
    sock_addr.sin_addr.s_addr = INADDR_ANY;
    ret = bind(sock_fd, (struct sockaddr*)&sock_addr, sizeof(struct sockaddr_in));
    if(ret < 0)
    {
        printf("bind Error:%m\n");
        close(sock_fd);
        sock_fd = -1;
        return -1;
    }
    return sock_fd;
}

void str_add(int sockfd)
{
    ssize_t n;
    char buf[1024]={0};
	struct sockaddr_in cltaddr;
	int cltlen;
	long arg1,arg2;
	getpeername(sockfd,(struct sockaddr*)&cltaddr,&cltlen);
again:
    while((n=read(sockfd,buf,1024))>0)
    {
		if(sscanf(buf,"%ld%ld",&arg1,&arg2) == 2)
			snprintf(buf,sizeof(buf),"%ld\n",arg1 + arg2);
		else
			snprintf(buf,sizeof(buf),"input error\n");
		n = strlen(buf);
        write(sockfd,buf,n);
    }
    if(n<0 && errno == EINTR)
        goto again;
    else if(n < 0)
        printf("str_add error:%m\n");
	else if(n == 0){
		printf("client <%s:%d> closed\n",inet_ntoa(cltaddr.sin_addr),ntohs(cltaddr.sin_port));
	}
	return ;
}

void sig_chld(int signo)
{
	pid_t pid;
	int stat;
	while((pid = waitpid(-1,&stat,WNOHANG)) > 0)
	{
		//printf("child %d terminated\n",pid);
	}
	return ;
}

int main(void)
{
    int fd=0,connfd;
    int clilen;
    pid_t pid;
    struct sockaddr_in srvaddr,cliaddr;

    fd=Create_socket(55560);
    listen(fd,5);
	signal(SIGCHLD,sig_chld);
    for(;;)
    {
        clilen = sizeof(cliaddr);
        connfd = accept(fd,(struct sockaddr*)&cliaddr,&clilen);
		printf("client <%s:%d> connected\n",inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port));
        if((pid = fork())==0)
        {
            close(fd);
            str_add(connfd);
			
    		struct sockaddr_in clitaddr;
			int clitlen;
			getpeername(connfd,(struct sockaddr*)&clitaddr,&clitlen);
            
			close(connfd);
            exit(0);
        }
        close(connfd);
    }

    return 0;
}
